package cn.demoncat.util.web;

import cn.demoncat.util.lang.ArrayUtil;
import cn.demoncat.util.lang.CollectionUtil;
import cn.demoncat.util.lang.MapUtil;
import cn.demoncat.util.lang.ParamEmptyUtil;
import cn.demoncat.util.lang.constant.StringConstant;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

/**
 * 
 * 
 * 描述：Cookie工具类
 *
 * @author yxl
 *
 * @version 2.0
 *
 * @since 2016年8月11日
 */
public final class CookieUtil {
 
	/**
	 * Cookie存活的最大时间：30*24*60*60
	 */
	public static final Integer MAX_AGE = 2592000;
	/**
	 * Cookie存活至会话结束(浏览器关闭)：-1
	 */
	public static final int SESSION_AGE = -1;
	
	/**
	 * 删除Cookie
	 * 
	 * @param response 
	 * @param domain 网址的domain(须同于创建原Cookie时的Domain，一级域名使用 .xxx.com)
	 * @param path 网址的路径(须同于创建原Cookie时的Path，默认"/")
	 * @param cookieName Cookie的键(须同于创建原Cookie时的键)
	 */
	public static void delCookie(HttpServletResponse response, String domain, String path, String cookieName){
		if (response == null) {
			return ;
		}
		if (ParamEmptyUtil.isBlank(domain,cookieName)) {
			return ;
		}
		path = StringUtils.isBlank(path) ? StringConstant.SEPARATOR : path;
		//创建同名Cookie
		Cookie coo = new Cookie(cookieName, StringConstant.EMPTY);
		//设置有效期为0，即立即过期
		coo.setMaxAge(0); 		
		//设置可获取cookie的URL路径、可获取cookie的DOMAIN
		coo.setPath(path);
		coo.setDomain(domain);
		//添加cookie，已存在则替换；因为过期时间置为0，所以会立即消失
		response.addCookie(coo);
	}
	
	/**
	 * 删除Cookie：路径 /
	 * 
	 * @param response 
	 * @param domain 网址的domain(须同于创建原Cookie时的Domain，一级域名使用 .xxx.com)
	 * @param cookieName Cookie的键(须同于创建原Cookie时的键)
	 */
	public static void delCookie(HttpServletResponse response, String domain, String cookieName){
		delCookie(response, domain, null,cookieName);
	}
	
	/**
	 * 设置Cookie，如果存在则替换存活时间和值
	 * 
	 * @param response
	 * @param domain 网址的domain(应用只能读写从属的domain下的cookie，一级域名使用 .xxx.com)
	 * @param path 网址的路径(应用只能读写从属的URL-Path下的cookie，默认 /)
	 * @param cookieName Cookie的键(cookie通过domain.path.cookieName保证唯一，如果已存在则设置时替换值和存活时间)
	 * @param value Cookie的值
	 * @param age Cookie的存活时间(秒；0表示立即清除，-1表示浏览器关闭时清除，最大30*24*60*60；默认-1)
	 */
	public static void setCookie(HttpServletResponse response, String domain, String path, String cookieName, String value, Integer age){
		if (response == null) {
			return ;
		}
		if (StringUtils.isAnyBlank(domain,cookieName)) {
			return ;
		}
		age = age == null || age < SESSION_AGE ? SESSION_AGE : age;
		age = age > 0  && age > MAX_AGE ? MAX_AGE : age;
		path = StringUtils.isBlank(path) ? StringConstant.SEPARATOR : path;
		//创建Cookie
		Cookie coo = new Cookie(cookieName, value);
		//设置存活时间
		coo.setMaxAge(age);
		//设置可获取cookie的URL路径、可获取cookie的DOMAIN
		coo.setPath(path);
		coo.setDomain(domain);
		//添加cookie，不存在时创建，已存在则替换
		response.addCookie(coo);
	}
	
	/**
	 * 设置Cookie，如果存在则替换存活时间和值：路径 /
	 * 
	 * @param response
	 * @param domain 网址的domain(应用只能读写从属的domain下的cookie，一级域名使用 .xxx.com)
	 * @param cookieName Cookie的键(cookie通过domain.path.cookieName保证唯一，如果已存在则设置时替换值和存活时间)
	 * @param value Cookie的值
	 * @param age Cookie的存活时间(秒；0表示立即清除，-1表示浏览器关闭时清除，最大30*24*60*60)
	 */
	public static void setCookie(HttpServletResponse response, String domain, String cookieName, String value, Integer age){
		 setCookie(response, domain,null, cookieName, value, age);
	}
	
	/**
	 * 设置Cookie，如果存在则替换存活时间和值：路径 / ，存活时间到浏览器关闭
	 * 
	 * @param response
	 * @param domain 网址的domain(应用只能读写从属的domain下的cookie，一级域名使用 .xxx.com)
	 * @param cookieName Cookie的键(cookie通过domain.path.cookieName保证唯一，如果已存在则设置时替换值和存活时间)
	 * @param value Cookie的值
	 */
	public static void setCookie(HttpServletResponse response, String domain, String cookieName, String value){
		 setCookie(response, domain,null, cookieName, value, null);
	}
	
	/**
	 * 获取Cookie值
	 * 
	 * @param request
	 * @param cookieName Cookie的键
	 * 
	 * @return Cookie的值
	 */
	public static String getCookie(HttpServletRequest request, String cookieName){
		if (request == null || StringUtils.isBlank(cookieName)) {
			return StringConstant.EMPTY;
		}
		//获取可读取的所有Cookies
		Cookie[] cookies = request.getCookies();
		if (cookies == null || cookies.length == 0) {
			return null;
		}
		//遍历Cookies，根据Cookie键获取值
		for (Cookie cookie : cookies) {
			if (cookieName.equals(cookie.getName())) {
				return cookie.getValue();
			}
		}
		return "";
	}
	 
	/**
	 * 获取发起HTTP请求时的Cookie头
	 * 
	 * @param cookies	Cookie键=值
	 * 
	 * @return Cookie：k1=v1;k2=v2
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年10月13日
	 */
	public static String getRequestCookie(Map<String,String> cookies) {
		if (MapUtil.isEmpty(cookies)) {
			return StringConstant.EMPTY;
		}
		StringBuilder sd = new StringBuilder();
		for (Entry<String, String> entry : cookies.entrySet()) {
			sd.append(entry.getKey()).append(StringConstant.EQUAL).append(UrlUtil.encode(entry.getValue())).append(StringConstant.SEMICOLON);
		}
		return StringUtils.removeEnd(sd.toString(), StringConstant.SEMICOLON);
	}
	
	/**
	 * 读取接收HTTP响应时的Cookie头
	 * 
	 * @param cookies	Set-Cookie：k=v; expires=Wed, 13-Nov-2019 05:44:57 GMT; Max-Age=2592000; path=/
	 * 
	 * @return Cookie键=值
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年10月13日
	 */
	public static Map<String,String> getResponseCookie(List<String> cookies) {
		Map<String, String> map = new HashMap<>();
		if (CollectionUtil.isNotEmpty(cookies)) {
			String[] split;
			for (String str : cookies) {
				str = str.substring(0, str.indexOf(StringConstant.SEMICOLON));
				split = StringUtils.split(str,StringConstant.EQUAL,2);
				map.put(split[0], UrlUtil.decode(ArrayUtil.get(split, 1)));
			}
		}
		return map;
	}

	/**
	 * 添加cookies到header
	 *
	 * @param header
	 * @param cookies
	 * @return
	 */
	public static Map<String,String> addCookie(Map<String,String> header, Map<String,String> cookies){
		if (header == null) {
			header = new HashMap<>();
		}
		if (MapUtils.isNotEmpty(cookies)) {
			header.put("Cookie", cookies.entrySet().stream().map(e -> e.getKey()+"="+e.getValue()).collect(Collectors.joining("; ")));
		}
		return header;
	}

	/**
	 * 添加cookies到header
	 *
	 * @param header
	 * @param name
	 * @param value
	 * @return
	 */
	public static Map<String,String> addCookie(Map<String,String> header, String name, String value){
		name = name +"="+ value;
		if (header == null) {
			header = new HashMap<>();
			header.put("Cookie", name);
		}else{
			value = header.get("Cookie");
			if (value == null) {
				header.put("Cookie", name);
			}else{
				header.put("Cookie", value +"; "+ name);
			}
		}
		return header;
	}
}
